package ru.ssau.customerManagement.controller.remoting;

import ru.ssau.customerManagement.controller.Controller;
import ru.ssau.customerManagement.controller.CreationException;
import ru.ssau.customerManagement.model.entities.Customer;
import ru.ssau.customerManagement.model.entities.CustomerLocation;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.*;
import java.net.Socket;
import java.util.List;

/**
 * Created by illabefat on 22.11.14.
 */
public class ClientController implements Controller {
    private final Socket server;
    private ObjectInputStream in;
    private ObjectOutputStream out;

    public ClientController(Socket server) throws IOException {
        this.server = server;
        in = new ObjectInputStream(this.server.getInputStream());
        out = new ObjectOutputStream(this.server.getOutputStream());
    }

    @Override
    public Customer getCustomer(Long id) {
        OperationResponse response = sendMessage(new OperationRequest("getCustomer", id));
        return (Customer) response.getObject();
    }

    @Override
    public void addCustomer(Customer customer) throws CreationException {
        OperationResponse response = sendMessage(new OperationRequest("addCustomer", customer));
        if (response.getException() != null && response.getException() instanceof CreationException)
            throw (CreationException) response.getException();
    }

    @Override
    public void replaceCustomer(Customer newCustomer) {
        sendMessage(new OperationRequest("replaceCustomer", newCustomer));
    }

    @Override
    public void deleteCustomer(Long customerId) {
        sendMessage(new OperationRequest("deleteCustomer", customerId));
    }

    @Override
    public void addCustomerLocation(CustomerLocation location) throws CreationException {
        OperationResponse response = sendMessage(new OperationRequest("addCustomerLocation", location));
        if (response.getException() != null && response.getException() instanceof CreationException)
            throw (CreationException) response.getException();
    }

    @Override
    public void replaceCustomerLocation(CustomerLocation location) {
        sendMessage(new OperationRequest("replaceCustomerLocation", location));
    }

    @Override
    public CustomerLocation getLocation(Long id) {
        OperationResponse response = sendMessage(new OperationRequest("getLocation", id));
        return (CustomerLocation) response.getObject();
    }

    @Override
    public void deleteCustomerLocation(Long customerLocationId) {
        sendMessage(new OperationRequest("deleteCustomerLocation", customerLocationId));
    }

    @Override
    public List<CustomerLocation> getLocationsByCustomer(Long customerId) {
        OperationResponse response = sendMessage(new OperationRequest("getLocationsByCustomer", customerId));
        return (List<CustomerLocation>) response.getObject();
    }

    @Override
    public List<Customer> getCustomers() {
        OperationResponse response = sendMessage(new OperationRequest("getCustomers"));
        return (List<Customer>) response.getObject();
    }

    @Override
    public boolean tryLockCustomer(Long id) {
        OperationResponse response = sendMessage(new OperationRequest("tryLockCustomer", id));
        return (Boolean) response.getObject();
    }

    @Override
    public void unlockCustomer(Long id) {
        sendMessage(new OperationRequest("unlockCustomer", id));
    }

    @Override
    public boolean tryLockCustomerLocation(Long id) {
        OperationResponse response = sendMessage(new OperationRequest("tryLockCustomerLocation", id));
        return (Boolean) response.getObject();
    }

    @Override
    public void unlockCustomerLocation(Long id) {
        sendMessage(new OperationRequest("unlockCustomerLocation", id));
    }

    private synchronized OperationResponse sendMessage(OperationRequest request) {
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(OperationRequest.class, OperationResponse.class,
                    Customer.class, CustomerLocation.class);
            Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
            StringWriter sw = new StringWriter();
            jaxbMarshaller.marshal(request, sw);
            String xmlString = sw.toString();
            //jaxbMarshaller.marshal(request, out);

            out.writeUTF(xmlString);
            out.flush();
            out.reset();

            String xmlResult = in.readUTF();

            OperationResponse res = (OperationResponse) jaxbUnmarshaller.unmarshal(new StringReader(xmlResult));
            return res;
        } catch (JAXBException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

